package pkgscanner;


import pkgscanner.annotations.AutoWired;
import pkgscanner.enums.BeanTypeEnum;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author 星环
 * @date 2023/3/9 20:24:54
 * @description
 */
public class MyContext {
    private Map<String,BeanDefinition> beanMap = new HashMap<>();

    public Map<String, BeanDefinition> getBeanMap() {
        return beanMap;
    }

    public void setBeanMap(Map<String, BeanDefinition> beanMap) {
        this.beanMap = beanMap;
    }

    public MyContext(String path){
        loadBeans(path);
    }

    private void loadBeans(String path) {
        Set<BeanDefinition> beanDefinitions = new SimplePackageScanner(path).doScan();
        beanDefinitions.forEach(beanDefinition -> {
            beanMap.put(beanDefinition.name,beanDefinition);
        });
        try {
            injectFileds();
        } catch (InvocationTargetException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 只支持注解在setter上的自动装配
     */
    private void injectFileds() throws InvocationTargetException, IllegalAccessException {
        for (String s : beanMap.keySet()) {
            BeanDefinition beanDef = beanMap.get(s);
            if(beanDef.beanType == BeanTypeEnum.PROTOTYPE){
                continue;
            }
            Object bean = beanDef.bean;
            Class<?> clazz = beanDef.clazz;
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                AutoWired awAnno = method.getAnnotation(AutoWired.class);
                if(awAnno == null){
                    continue;
                }
                String beanName = awAnno.value();
                if("".equals(beanName)){
                    beanName = method.getName().substring(3);
                    beanName = Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
                }
                Object val = getBean(beanName);
                method.invoke(bean,val);
            }
        }
    }

    public Object getBean(String name){
        BeanDefinition beanDefinition = beanMap.get(name);
        if(beanDefinition != null ){
            if (beanDefinition.beanType == BeanTypeEnum.SINGLETON){
                return beanDefinition.bean;
            }else {//PROTOTYPE
                return createBean(beanDefinition.constructor);
            }
        }
        return null;
    }

    private Object createBean(Constructor<?> constructor) {
        try {
            return constructor.newInstance();
        } catch (Exception ignored){}
        return null;
    }
}
